package com.hotacorp.opencloud.userservice.service.impl;

import java.io.Serializable;
import java.time.Duration;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hotacorp.opencloud.common.authcommon.SysClientBean;
import com.hotacorp.opencloud.common.mybatisplus.PageData;
import com.hotacorp.opencloud.common.mybatisplus.Query;
import com.hotacorp.opencloud.userservice.dao.OauthClientDetailsDao;
import com.hotacorp.opencloud.userservice.entity.OauthClientDetailsEntity;
import com.hotacorp.opencloud.userservice.service.OauthClientDetailsService;
import com.hotacorp.opencloud.userservice.util.UserConstants;

/**
 * 客户端接口实现
 * @author lwg
 *
 */
@Service("oauthClientDetailsService")
public class OauthClientDetailsServiceImpl extends ServiceImpl<OauthClientDetailsDao, OauthClientDetailsEntity> implements OauthClientDetailsService {
	@Autowired
	private StringRedisTemplate redisTemplate;
	private PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    @Override
    public PageData queryPage(Map<String, Object> params) {
    	QueryWrapper<OauthClientDetailsEntity> query = new QueryWrapper<OauthClientDetailsEntity>();
    	if (StringUtils.isNotBlank((String)params.get("clientId"))) query.eq("client_id", params.get("clientId"));
        IPage<OauthClientDetailsEntity> page = this.page(
                new Query<OauthClientDetailsEntity>().getPage(params),
                query
        );

        return new PageData(page);
    }

	@Override
	public SysClientBean loadClientByClientId(String clientId) {
		String dddd = redisTemplate.boundValueOps(UserConstants.CLIENT_KEY + ":" + clientId).get();
		if (dddd == null) {
			QueryWrapper<OauthClientDetailsEntity> wrapper = new QueryWrapper<OauthClientDetailsEntity>();
			wrapper.eq("client_id", clientId);
			OauthClientDetailsEntity entity = this.baseMapper.selectOne(wrapper);
			if (entity != null) {
				SysClientBean retBean = new SysClientBean();
				retBean.setAccessTokenValidity(entity.getAccessTokenValidity());
				retBean.setClientId(entity.getClientId());
				retBean.setClientSecret(entity.getClientSecret());
				retBean.setClientSecretStr(entity.getClientSecretStr());
				retBean.setRefreshTokenValidity(entity.getRefreshTokenValidity());
				retBean.setAuthorities(getList(entity.getAuthorities()));
				retBean.setAuthorizedGrantTypes(getSet(entity.getAuthorizedGrantTypes()));
				retBean.setAutoapprove(getSet(entity.getAutoapprove()));
				retBean.setRegisteredRedirectUri(getSet(entity.getWebServerRedirectUri()));
				retBean.setResourceIds(getSet(entity.getResourceIds()));
				retBean.setScope(getSet(entity.getScope()));
				String sss = JSON.toJSONString(retBean);
				redisTemplate.boundValueOps(UserConstants.CLIENT_KEY + ":" + clientId).set(sss, Duration.ofMinutes(10));
				return retBean;
			} else {
				redisTemplate.boundValueOps(UserConstants.CLIENT_KEY + ":" + clientId).set("", Duration.ofMinutes(10 +(new Random()).nextInt(10)));
				return null;
			}
		} else if ("".equals(dddd)) {
			return null;
		} else {
			redisTemplate.boundValueOps(UserConstants.CLIENT_KEY + ":" + clientId).expire(10, TimeUnit.MINUTES);
			SysClientBean retBean = JSON.parseObject(dddd, SysClientBean.class);
			return retBean;
		}
	}

	private List<String> getList(String str) {
		if (StringUtils.isNotBlank(str)) {
			return Arrays.asList(StringUtils.split(str, ","));
		}
		return Collections.emptyList();
	}

	private Set<String> getSet(String str) {
		if (StringUtils.isNotBlank(str)) {
			return new HashSet<>(Arrays.asList(StringUtils.split(str, ",")));
		}
		return Collections.emptySet();
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void saveClient(OauthClientDetailsEntity entity) {
		entity.setClientSecret(passwordEncoder.encode(entity.getClientSecretStr()));
		super.save(entity);
		
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updateClient(OauthClientDetailsEntity entity) {
		if(StringUtils.isBlank(entity.getClientSecretStr())){
			entity.setClientSecret(null);
			entity.setClientSecretStr(null);
		}else{
			entity.setClientSecret(passwordEncoder.encode(entity.getClientSecretStr()));
		}
		super.updateById(entity);
		redisTemplate.delete(UserConstants.CLIENT_KEY + ":" + entity.getClientId());
	}
	
	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean removeByIds(Collection<? extends Serializable> idList) {
		List<OauthClientDetailsEntity> list = baseMapper.selectBatchIds(idList);
		baseMapper.deleteBatchIds(idList);
		list.forEach(en->{
			redisTemplate.delete(UserConstants.CLIENT_KEY + ":" + en.getClientId());
		});
		return true;
	}

}